﻿Imports System
Imports System.Collections.Generic
Imports System.DirectoryServices

Namespace System.Workflow.Activities
    <Serializable> _
    Friend NotInheritable Class DirectoryRedirect
        Implements IDirectoryOperation
        ' Methods
        Public Sub New(ByVal getPropertyName As String, ByVal searchPropertyName As String)
            Me.New(getPropertyName, searchPropertyName, False)
        End Sub

        Public Sub New(ByVal getPropertyName As String, ByVal searchPropertyName As String, ByVal recursive As Boolean)
            If (getPropertyName Is Nothing) Then
                Throw New ArgumentNullException("getPropertyName")
            End If
            If (searchPropertyName Is Nothing) Then
                Throw New ArgumentNullException("searchPropertyName")
            End If
            Me.m_getPropertyName = getPropertyName
            Me.m_searchPropertyName = searchPropertyName
            Me.m_recursive = recursive
        End Sub

        Private Function CreateSearcher(ByVal rootEntry As DirectoryEntry, ByVal currentEntry As DirectoryEntry) As DirectorySearcher
            Dim searcher As New DirectorySearcher(rootEntry)
            Dim values As PropertyValueCollection = currentEntry.Properties.Item(Me.m_getPropertyName)
            searcher.Filter = String.Concat(New Object() { "(", Me.m_searchPropertyName, "=", values.Item(0), ")" })
            Return searcher
        End Function

        Public Sub GetResult(ByVal rootEntry As DirectoryEntry, ByVal currentEntry As DirectoryEntry, ByVal response As List([Of] DirectoryEntry))
            If (rootEntry Is Nothing) Then
                Throw New ArgumentNullException("rootEntry")
            End If
            If (currentEntry Is Nothing) Then
                Throw New ArgumentNullException("currentEntry")
            End If
            If (response Is Nothing) Then
                Throw New ArgumentNullException("response")
            End If
            If Not Me.m_recursive Then
                [Using] searcher As DirectorySearcher = Me.CreateSearcher(rootEntry, currentEntry)
                    Dim result As SearchResult
                    For Each result In searcher.FindAll
                        response.Add(result.GetDirectoryEntry)
                    Next
                    Return
                End [Using]
            End If
            Dim dictionary As New Dictionary([Of] Guid, DirectoryEntry)
            Dim stack As New Stack([Of] DirectoryEntry)
            stack.Push(currentEntry)
            Do While (stack.Count <> 0)
                Dim entry As DirectoryEntry = stack.Pop
                [Using] searcher2 As DirectorySearcher = Me.CreateSearcher(rootEntry, entry)
                    Dim result2 As SearchResult
                    For Each result2 In searcher2.FindAll
                        Dim directoryEntry As DirectoryEntry = result2.GetDirectoryEntry
                        If Not dictionary.ContainsKey(directoryEntry.Guid) Then
                            dictionary.Add(directoryEntry.Guid, directoryEntry)
                        End If
                        stack.Push(directoryEntry)
                    Next
                    [Continue] Do
                End [Using]
            Loop
            response.AddRange(dictionary.Values)
        End Sub


        ' Fields
        Private m_getPropertyName As String
        Private m_recursive As Boolean
        Private m_searchPropertyName As String
    End Class
End Namespace

